package com.atguigu.system.filter;

import com.atguigu.common.result.Result;
import com.atguigu.common.result.ResultCodeEnum;
import com.atguigu.common.util.ResponseUtil;
import com.atguigu.model.system.SysUser;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 验证请求头中是否存在token令牌，存在并且有效，放行，否则，无权访问
 */
public class TokenAuthenticationFilter extends OncePerRequestFilter {

    RedisTemplate redisTemplate;

    public TokenAuthenticationFilter(RedisTemplate redisTemplate){
        this.redisTemplate = redisTemplate;
    }

    //被父类的doFilter方法来调用。对请求过滤。
    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {

        //1.如果是登录请求路径，放行
        // url   http://localhost:8800/admin/system/index/login
        // uri   /admin/system/index/login
        String requestURI = request.getRequestURI();
        if("/admin/system/index/login".equals(requestURI)){
            filterChain.doFilter(request,response); //放行

            return ; //放行回来时，不继续往下执行。
        }

        //获取认证对象，存储到SecurityContext中。
        Authentication authentication = getAuthentication(request);

        if(authentication != null){ //令牌正确，已经认证
            SecurityContextHolder.getContext().setAuthentication(authentication);
            filterChain.doFilter(request,response); //放行
        }else{ //令牌不对，无法获取认证对象
            ResponseUtil.out(response, Result.build(null, ResultCodeEnum.PERMISSION));
        }
    }

    //根据token令牌构建认证对象
    private Authentication getAuthentication(HttpServletRequest request) {
        //前端登录后，将令牌存储在请求头中 ,参考：/src/utils/request.js  27行
        String token = request.getHeader("token");
        if(!StringUtils.isEmpty(token)){
            SysUser sysUser = (SysUser)redisTemplate.boundValueOps(token).get();
            if(sysUser!=null){
                if(sysUser.getUserPermsList()!=null && sysUser.getUserPermsList().size()>0){
                    //将权限标识（"bnt.sysUser.list"）构建成权限对象（SimpleGrantedAuthority implements GrantedAuthority）
                    // List<String> ===>>>  List<GrantedAuthority>
                    List<GrantedAuthority> authorities =  sysUser.getUserPermsList()
                            .stream().filter(code -> !StringUtils.isEmpty(code))
                            .map(code-> new SimpleGrantedAuthority(code)).collect(Collectors.toList());
                    //认证后  认证对象
                    return new UsernamePasswordAuthenticationToken(sysUser,null,authorities);
                }else{
                    return new UsernamePasswordAuthenticationToken(sysUser,null, Collections.emptyList());
                }
            }
        }
        return null;
    }


}
